﻿using System;
using System.Collections.Generic;

using System.Text;
using Xeno.Core;

using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace Xeno.Module
{
    public class XenoMesh : XenoModule
    {
        public List<XenoVertex> Vertices { get; set; }
        public List<XenoTriangle> Triangles { get; set; }
        [XenoProp("Scale",typeof(Vector3))]
        public Vector3 Scale { get; set; }
        [XenoProp("Test Value",typeof(float))]
        public float TestValue;
        [XenoProp("Flip Normals",typeof(bool))]
        public bool FlipNormals { get; set; }

        public void CleanMesh()
        {
            while (Triangles.Contains(null))
            {
                Triangles.Remove(null);
            }
        }
        public void UpdateNormals()
        {
            CleanMesh();
            foreach (var v in Vertices)
            {

                v.Normal = v.Tangent = v.BiNormal = Vector3.Zero;

            }
            int[] vc = new int[Vertices.Count];
            for (int i = 0; i < Vertices.Count; i++)
            {
                vc[i] = 0;
            }
            int vc2 = Vertices.Count;
            foreach (var t in Triangles)
            {
                Vector3 norm, tangent, binormal;
                norm = tangent = binormal = Vector3.Zero;
                if (t == null) continue;
                if (t.V1 >= vc2 || t.V2 >= vc2 || t.V3 >= vc2)
                {
                }
                else
                {
                    CalculateNormals(ref norm, ref tangent, ref binormal, Vertices[t.V1].Position, Vertices[t.V2].Position, Vertices[t.V3].Position, Vertices[t.V1].Tex0, Vertices[t.V2].Tex0, Vertices[t.V3].Tex0);
                }
                    Vertices[t.V1].Normal = norm;
                Vertices[t.V2].Normal = norm;
                Vertices[t.V3].Normal = norm;
                Vertices[t.V1].Tangent = tangent;
                Vertices[t.V2].Tangent = tangent;
                Vertices[t.V3].Tangent = tangent;
                Vertices[t.V1].BiNormal = binormal;
                Vertices[t.V2].BiNormal = binormal;
                Vertices[t.V3].BiNormal = binormal;
                vc[t.V1]++;
                vc[t.V2]++;
                vc[t.V3]++;
            }
            if (FlipNormals)
            {
                int index = 0;
                foreach (XenoVertex v in Vertices)
                {

                   
                    v.Normal = -v.Normal;// / vc[index];
                   // v.BiNormal = -v.BiNormal;// / vc[index];
                   // v.Tangent = -v.Tangent;// / vc[index];
                    //v.Normal.Normalize();
                    //v.Tangent.Normalize();
                    //v.BiNormal.Normalize();
                    index++;

                }

            }
        }

        internal void CalculateNormals(ref Vector3 normal, ref Vector3 tangent, ref Vector3 binormal, Vector3 vt1, Vector3 vt2, Vector3 vt3, Vector3 tc1, Vector3 tc2, Vector3 tc3)
        {
            Vector3 v1 = vt1-vt2;
            Vector3 v2 = vt3-vt1;
            normal = Vector3.Cross(v2, v1);
            normal.Normalize();
          
            // binormal

            float deltaX1 = tc1.X - tc2.X;
            float deltaX2 = tc3.X - tc1.X;
            binormal = (v1 * deltaX2) - (v2 * deltaX1);
            binormal.Normalize();

            // tangent

            float deltaY1 = tc1.Y - tc2.Y;
            float deltaY2 = tc3.Y - tc1.Y;
            tangent = (v1 * deltaY2) - (v2 * deltaY1);
            tangent.Normalize();

            // adjust

            Vector3 txb = Vector3.Cross(tangent,binormal);
            if (Vector3.Dot(txb,normal) < 0.0f)
            {
                tangent *= -1.0f;
                binormal *= -1.0f;
            }

        }

        public Vector3[] BoundingBox
        {
            get
            {
                float sx, sy,sz, bx, by,bz;
                sx = sy = sz = bx = by = bz = 0;
                bool first = true;
                foreach (var v in Vertices)
                {
                    Vector3 pos = v.Position;
                    if (first)
                    {
                        first = false;
                        sx = pos.X;
                        sy = pos.Y;
                        sz = pos.Z;
                        bx = sx;
                        by = sy;
                        bz = sz;
                    }
                    if (pos.X<sx) 
                    {
                        sx = pos.X;
                    }
                    if (pos.X > bx) bx = pos.X;
                    if (pos.Y < sy) sy = pos.Y;
                    if (pos.Y > by) by = pos.Y;
                    if (pos.Z < sz) sz = pos.Z;
                    if (pos.Z > bz) bz = pos.Z;
                }
                Vector3[] ret = new Vector3[2];
                ret[0] = new Vector3(sx,sy,sz);
                ret[1] = new Vector3(bx,by,bz);
                return ret;

            }



        }
        
        public XenoMesh()
            : base()
        {
            ResetMesh();
        }
       
        private void ResetMesh()
        {
            Name = "XenoMod_Mesh";
            ModuleAuthor = "Antony Wells";
            ModuleVersionString = "Mesh Module - Version CTP 1";
            Vertices = new List<XenoVertex>();
            Triangles = new List<XenoTriangle>();
            FlipNormals = false;
        }

        public XenoVertex AddVertex
        {
            set
            {
                Vertices.Add(value); 
            }
        }
        public XenoVertex[] AddVertices
        {
            set
            {
                Vertices.AddRange(value);
            }
        }

        public XenoTriangle AddTriangle
        {
            set
            {
                Triangles.Add(value);
            }
        }
        public XenoTriangle[] AddTriangles
        {
            set
            {
                Triangles.AddRange(value);
            }
        }

        public XenoVertex this[int index]
        {
            get
            {
                return Vertices[index];
            }
            set
            {

                Vertices[index] = value;
            }
        }
      
        public XenoVertex Add(XenoVertex vertex)
        {
            AddVertex = vertex;
            return vertex;
        }
        public XenoVertex[] Add(XenoVertex[] vertices)
        {
            AddVertices = vertices;
            return vertices;
        }
        public XenoTriangle Add(XenoTriangle triangle)
        {
            AddTriangle = triangle;
            return triangle;
        }
        public XenoTriangle[] Add(XenoTriangle[] triangles)
        {
            AddTriangles = triangles;
            return triangles;
        }
        public void AddTri(int v1, int v2, int v3)
        {
            AddTriangle = new XenoTriangle(v1, v2, v3);
        }

        public override void DoUpdate()
        {
            
        }
        public override void DoRender()
        {
                        
        }
    }

    public class XenoVertex
    {
        public Vector3 Position;
        public Vector3 Normal;
        public Vector3 Tangent;
        public Vector3 BiNormal;
        public Vector3 Tex0;
        public Vector3 Tex1;
        public Vector4 Color;
        public XenoVertex(Vector3 pos, Vector3 tex0)
        {
            Position = pos;
            Tex0 = tex0;
            Normal = Vector3.Normalize(pos);
            Color = new Vector4(1, 1, 1, 1);
        }
        public XenoVertex(Vector3 pos)
        {
            Position = pos;
            Normal = Vector3.Normalize(Position);
            Color = new Vector4(1, 1, 1, 1);
        }
        public XenoVertex(Vector3 pos, Vector3 norm, Vector3 tex)
        {
            Position = pos;
            Normal = norm;
            Tex0 = tex;
            Color = new Vector4(1, 1, 1,1);
        
        }
    }

    public class XenoTriangle
    {
        public int V1, V2, V3;
        public XenoTriangle(int v1, int v2, int v3)
        {
            V1 = v1;
            V2 = v2;
            V3 = v3;
        }
    }
}
